use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use crate::conn::Connection;
use crate::error::{Result, VerticaError};

/// Connection pool configuration
#[derive(Debug, Clone)]
pub struct PoolConfig {
    /// Maximum number of connections in the pool
    pub max_connections: usize,
    /// Connection timeout duration
    pub connection_timeout: Duration,
}

impl Default for PoolConfig {
    fn default() -> Self {
        PoolConfig {
            max_connections: 10,
            connection_timeout: Duration::from_secs(30),
        }
    }
}

/// A simple connection pool
pub struct ConnectionPool {
    config: PoolConfig,
    connections: Mutex<VecDeque<Connection>>,
}

impl ConnectionPool {
    /// Create a new connection pool
    pub fn new(config: PoolConfig) -> Arc<Self> {
        Arc::new(ConnectionPool {
            config,
            connections: Mutex::new(VecDeque::new()),
        })
    }

    /// Get a connection from the pool
    pub fn get_connection(&self) -> Result<Connection> {
        let mut connections = self.connections.lock()
            .map_err(|_| VerticaError::Connection("Failed to lock connections".to_string()))?;

        if let Some(connection) = connections.pop_front() {
            Ok(connection)
        } else {
            Err(VerticaError::Connection("No connections available".to_string()))
        }
    }

    /// Return a connection to the pool
    pub fn return_connection(&self, connection: Connection) -> Result<()> {
        let mut connections = self.connections.lock()
            .map_err(|_| VerticaError::Connection("Failed to lock connections".to_string()))?;

        if connections.len() < self.config.max_connections {
            connections.push_back(connection);
        }

        Ok(())
    }

    /// Get the current number of connections
    pub fn size(&self) -> usize {
        self.connections.lock()
            .map(|c| c.len())
            .unwrap_or(0)
    }

    /// Clear all connections
    pub fn clear(&self) -> Result<()> {
        let mut connections = self.connections.lock()
            .map_err(|_| VerticaError::Connection("Failed to lock connections".to_string()))?;
        connections.clear();
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_pool_config() {
        let config = PoolConfig::default();
        assert_eq!(config.max_connections, 10);
        assert_eq!(config.connection_timeout, Duration::from_secs(30));
    }

    #[test]
    fn test_pool_creation() {
        let config = PoolConfig::default();
        let pool = ConnectionPool::new(config);
        assert_eq!(pool.size(), 0);
    }

    #[test]
    fn test_pool_size() {
        let config = PoolConfig::default();
        let pool = ConnectionPool::new(config);
        assert_eq!(pool.size(), 0);
    }

    #[test]
    fn test_pool_clear() {
        let config = PoolConfig::default();
        let pool = ConnectionPool::new(config);
        assert!(pool.clear().is_ok());
    }
}